/**
 * 下载核心模块 - 处理实际的下载逻辑和断点续传
 */

import ChatHistory from '../ChatHistory.js'

class DownloadCore {
  
  // 存储当前下载任务和断点续传数据
  static resumableDownloads = new Map()
  static activeDownloadTasks = new Map() // 存储所有活跃的下载任务
  static downloadCancelHandlers = new Map() // 存储取消处理器
  
  /**
   * 开始下载
   * @param {Object} options 下载参数
   */
  static startDownload(options) {
    const {
      item,
      itemName,
      itemType,
      downloadUrl,
      targetDir,
      category,
      historyHandler,
      getDirectory,
      getDefaultExtension
    } = options

    const downloadId = `${itemName}_${itemType}_${Date.now()}`

    // 检查是否有可恢复的下载
    const resumableInfo = this.getResumableDownload(itemName, itemType)

    // 记录下载开始到聊天历史
    ChatHistory.addMessage({
      type: 'system',
      content: resumableInfo ? `继续下载${category}《${itemName}》到${targetDir}` : `开始下载${category}《${itemName}》到${targetDir}`,
      sender: 'system',
      category: category,
      data: item
    })

    // 发送下载开始事件
    uni.$emit('downloadStart', {
      id: downloadId,
      gameName: itemName,
      gameType: itemType,
      targetDir: targetDir,
      isResume: !!resumableInfo
    })

    // #ifdef APP-PLUS
    this.startAppDownload(downloadId, options, resumableInfo)
    // #endif

    // #ifndef APP-PLUS
    this.startBrowserDownload(downloadId, options)
    // #endif

    return downloadId
  }

  // APP环境下载
  static startAppDownload(downloadId, options, resumableInfo) {
    const {
      downloadUrl
    } = options

    // 先下载到临时文件，成功后再移动
    this.downloadToTempFile(downloadId, downloadUrl, options)
  }

  // 下载到临时文件
  static downloadToTempFile(downloadId, downloadUrl, options) {
    const {
      itemName,
      itemType
    } = options

    const downloadTask = uni.downloadFile({
      url: downloadUrl,
      success: (res) => {
        if (res.statusCode === 200) {
          this.handleDownloadSuccess(downloadId, res.tempFilePath, options)
        } else {
          this.handleDownloadError(downloadId, `服务器响应错误: ${res.statusCode}`, options, false)
        }
      },
      fail: (err) => {
        let errorMsg = '下载失败'

        if (err.errMsg) {
          if (err.errMsg.includes('url not valid')) {
            errorMsg = '下载地址无效'
          } else if (err.errMsg.includes('network')) {
            errorMsg = '网络连接失败'
          } else if (err.errMsg.includes('timeout')) {
            errorMsg = '网络超时'
          }
        }

        this.handleDownloadError(downloadId, errorMsg, options, true)
      }
    })

    // 存储任务引用
    this.activeDownloadTasks.set(downloadId, downloadTask)

    // 设置取消处理器
    this.setupCancelHandler(downloadId, downloadTask, options)

    // 监听下载进度
    downloadTask.onProgressUpdate((res) => {
      // 保存进度信息以便断点继续
      this.saveResumableDownload({
        id: downloadId,
        itemName: options.itemName,
        itemType: options.itemType,
        downloadUrl: downloadUrl,
        targetDir: options.targetDir,
        item: options.item,
        progress: res.progress,
        totalBytesWritten: res.totalBytesWritten,
        totalBytesExpectedToWrite: res.totalBytesExpectedToWrite,
        lastUpdate: Date.now()
      })

      this.updateDownloadProgress(res.progress, res.totalBytesWritten, res.totalBytesExpectedToWrite, options.itemName, options.itemType)

      // 发送进度事件
      uni.$emit('downloadProgress', {
        id: downloadId,
        progress: res.progress,
        totalBytesWritten: res.totalBytesWritten,
        totalBytesExpectedToWrite: res.totalBytesExpectedToWrite
      })
    })
  }


  // 处理下载成功
  static handleDownloadSuccess(downloadId, tempFilePath, options) {
    const {
      item,
      itemName,
      itemType,
      historyHandler,
      getDirectory,
      getDefaultExtension
    } = options

    // 清除可恢复信息
    this.clearResumableDownload(itemName, itemType)

    // 从活跃任务中移除
    this.activeDownloadTasks.delete(downloadId)
    this.downloadCancelHandlers.delete(downloadId)

    // 发送完成事件（临时文件）
    uni.$emit('downloadComplete', {
      id: downloadId,
      gameName: itemName,
      gameType: itemType,
      filePath: tempFilePath,
      targetDir: getDirectory ? getDirectory(itemType) : options.targetDir,
      isTempFile: true
    })

    // 尝试移动文件到目标目录
    this.moveFileToTargetDirectory(tempFilePath, item, itemType, getDirectory, getDefaultExtension, downloadId, itemName)
  }

  // 移动到目标目录
  static moveFileToTargetDirectory(tempFilePath, item, itemType, getDirectory, getDefaultExtension, downloadId, itemName) {
    if (!getDirectory) {
      console.log('未提供目录获取方法，文件保留在临时位置')
      return
    }

    const targetDir = getDirectory(itemType)
    const fileExtension = getDefaultExtension ? getDefaultExtension(itemType) : '.zip'
    // 修复重复扩展名问题
    let fileName = itemName;
    if (!itemName.endsWith(fileExtension)) {
      fileName = `${itemName}${fileExtension}`;
    }

    // 直接使用Download目录作为基础路径
    plus.io.requestFileSystem(plus.io.PUBLIC_DOWNLOADS,
      (fs) => {
        this.moveFileWithPlusIO(tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType, fs.root)
      },
      (error) => {
        // 作为备选方案，仍然尝试原来的逻辑
        plus.io.resolveLocalFileSystemURL('file:///storage/emulated/0',
          (rootEntry) => {
            this.moveFileWithPlusIO(tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType, rootEntry);
          },
          (rootError) => {
            this.handleFileMoveError('无法访问存储目录', tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType);
          }
        );
      }
    )
  }

  // 使用 plus.io API 移动文件
  static moveFileWithPlusIO(tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType, baseEntry) {
    // 确保目标目录存在（基于Download目录）
    this.ensureDirectoryExists(targetDir, (success, dirEntry) => {
      if (success && dirEntry) {
        this.copyFileToDirectory(tempFilePath, dirEntry, fileName, downloadId, itemName, item, itemType);
      } else {
        this.handleFileMoveError('目录创建失败', tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType);
      }
    }, baseEntry);
  }

  // 确保目录存在
  static ensureDirectoryExists(targetDir, callback, baseEntry = null) {
    // 如果提供了基础目录条目，则直接使用
    if (baseEntry) {
      // 从提供的基础目录开始创建子目录
      this.createDirectoryRecursivelyFromBase(baseEntry, targetDir, callback)
      return
    }

    // 先尝试直接解析目录
    const fullPath = targetDir.startsWith('/storage/emulated/0') ? 
      `file://${targetDir}` : 
      `file:///storage/emulated/0${targetDir.startsWith('/') ? targetDir : '/' + targetDir}`;
    
    plus.io.resolveLocalFileSystemURL(fullPath,
      (dirEntry) => {
        callback(true, dirEntry)
      },
      (error) => {
        this.createDirectoryRecursively(targetDir, callback)
      }
    )
  }

  // 递归创建目录
  static createDirectoryRecursively(targetDir, callback) {
    // 确保路径以/开头
    const normalizedPath = targetDir.startsWith('/') ? targetDir : '/' + targetDir;
    const parts = normalizedPath.split('/').filter(part => part.length > 0);

    // 直接使用Download目录作为基础
    plus.io.requestFileSystem(plus.io.PUBLIC_DOWNLOADS,
      (fs) => {
        this.createDirRecursive(fs.root, parts, 0, callback);
      },
      (fsError) => {
        callback(false, null);
      }
    );
  }

  // 递归创建目录（从指定基础目录开始）
  static createDirectoryRecursivelyFromBase(baseEntry, targetDir, callback) {
    // 确保路径以/开头
    const normalizedPath = targetDir.startsWith('/') ? targetDir : '/' + targetDir;
    const parts = normalizedPath.split('/').filter(part => part.length > 0);

    this.createDirRecursive(baseEntry, parts, 0, callback);
  }

  // 递归创建目录的辅助函数
  static createDirRecursive(parentEntry, pathParts, index, callback) {
    if (index >= pathParts.length) {
      callback(true, parentEntry);
      return;
    }

    const dirName = pathParts[index];
    
    parentEntry.getDirectory(dirName, { create: true },
      (dirEntry) => {
        this.createDirRecursive(dirEntry, pathParts, index + 1, callback);
      },
      (error) => {
        // 针对Android 10+的特殊处理
        if (error.code === 15) { // Scoped Storage错误
          callback(false, null);
          return;
        }
        
        // 尝试更宽松的创建方式
        parentEntry.getDirectory(dirName, { create: true, exclusive: false },
          (dirEntry) => {
            this.createDirRecursive(dirEntry, pathParts, index + 1, callback);
          },
          (error2) => {
            callback(false, null);
          }
        );
      }
    );
  }

  // 复制文件到目录
  static copyFileToDirectory(tempFilePath, dirEntry, fileName, downloadId, itemName, item, itemType) {
    // 首先解析源文件
    plus.io.resolveLocalFileSystemURL(tempFilePath,
        (sourceEntry) => {
          // 检查目标文件是否已存在
          dirEntry.getFile(fileName, { create: false },
              (existingFile) => {
                existingFile.remove(() => {
                  this.performFileCopy(sourceEntry, dirEntry, fileName, downloadId, itemName, item, itemType)
                }, (removeError) => {
                  this.performFileCopy(sourceEntry, dirEntry, fileName, downloadId, itemName, item, itemType)
                })
              },
              (notFoundError) => {
                // 文件不存在，直接复制
                this.performFileCopy(sourceEntry, dirEntry, fileName, downloadId, itemName, item, itemType)
              }
          )
        },
        (resolveError) => {
          this.handleFileMoveError('源文件不可用', tempFilePath, dirEntry.fullPath, fileName, downloadId, itemName, item, itemType)
        }
    )
  }

  // 执行文件复制
  static performFileCopy(sourceEntry, dirEntry, fileName, downloadId, itemName, item, itemType) {
    sourceEntry.copyTo(dirEntry, fileName,
        (newEntry) => {
          // 发送文件保存成功事件
          uni.$emit('fileSaveSuccess', {
            itemName: itemName,
            filePath: newEntry.fullPath,
            fileName: fileName,
            downloadId: downloadId
          })

          // 添加到下载历史
          if (typeof historyHandler !== 'undefined' && historyHandler.addDownloadRecord) {
            historyHandler.addDownloadRecord(item, newEntry.fullPath, itemType)
          }

          // 删除临时文件
          sourceEntry.remove(() => {
          }, (removeError) => {
          })
        },
        (copyError) => {
          this.handleFileMoveError('文件复制失败', sourceEntry.fullPath, dirEntry.fullPath, fileName, downloadId, itemName, item, itemType)
        }
    )
  }

  // 处理文件移动错误
  static handleFileMoveError(error, tempFilePath, targetDir, fileName, downloadId, itemName, item, itemType) {
    uni.$emit('fileSaveError', {
      itemName: itemName,
      tempPath: tempFilePath,
      targetDir: targetDir,
      fileName: fileName,
      error: error,
      downloadId: downloadId
    })

    // 文件保留在临时位置，仍然记录到历史
    if (typeof historyHandler !== 'undefined' && historyHandler.addDownloadRecord) {
      historyHandler.addDownloadRecord(item, tempFilePath, itemType)
    }
  }

  // 处理下载错误
  static handleDownloadError(downloadId, errorMsg, options, canResume = false) {
    const { itemName, itemType, category } = options

    // 从活跃任务中移除
    this.activeDownloadTasks.delete(downloadId)
    this.downloadCancelHandlers.delete(downloadId)

    // 发送错误事件
    uni.$emit('downloadError', {
      id: downloadId,
      message: errorMsg,
      canResume: canResume
    })

    // 显示用户友好的错误提示
    let userFriendlyMsg = '下载失败，请检查网络连接'
    if (errorMsg.includes('地址无效')) {
      userFriendlyMsg = '下载地址无效，请联系管理员'
    } else if (errorMsg.includes('超时')) {
      userFriendlyMsg = '网络连接超时，请重试'
    }

    uni.showToast({
      title: userFriendlyMsg,
      icon: 'none',
      duration: 3000
    })

    // 如果可恢复，保存断点信息
    if (canResume) {
      this.saveResumableDownload({
        id: downloadId,
        itemName: itemName,
        itemType: itemType,
        downloadUrl: options.downloadUrl,
        targetDir: options.targetDir,
        item: options.item,
        failedAt: Date.now()
      })
    }

    // 记录到聊天历史
    ChatHistory.addMessage({
      type: 'system',
      content: `下载《${itemName}》失败: ${userFriendlyMsg}`,
      sender: 'system',
      category: category
    })
  }

  // 设置取消处理器
  static setupCancelHandler(downloadId, downloadTask, options) {
    const cancelHandler = (data) => {
      if (data && (data.id === downloadId || data.downloadId === downloadId)) {
        const task = this.activeDownloadTasks.get(downloadId)
        if (task) {
          task.abort()
        }

        // 从活跃任务中移除
        this.activeDownloadTasks.delete(downloadId)
        this.downloadCancelHandlers.delete(downloadId)

        // 清除数据
        this.clearResumableDownload(data.itemName || options.itemName, data.itemType || options.itemType)

        // 移除事件监听器
        uni.$off('downloadCancel', cancelHandler)
        uni.$off('downloadPause', pauseHandler)
        uni.$off('downloadResume', resumeHandler)
      }
    }

    // 监听暂停和继续事件
    const pauseHandler = (data) => {
      if (data && data.id === downloadId) {
        this.pauseDownload(downloadId, data.itemName, data.itemType)
      }
    }

    const resumeHandler = (data) => {
      if (data && data.id === downloadId) {
        // 重新开始下载
        this.startDownload({
          ...options,
          itemName: data.itemName,
          itemType: data.itemType
        })
      }
    }

    // 存储取消处理器并监听取消事件
    this.downloadCancelHandlers.set(downloadId, cancelHandler)
    uni.$on('downloadCancel', cancelHandler)
    uni.$on('downloadPause', pauseHandler)
    uni.$on('downloadResume', resumeHandler)
  }

  // 浏览器环境下载
  static startBrowserDownload(downloadId, options) {
    const {
      itemName,
      itemType,
      downloadUrl,
      getDefaultExtension,
      getDirectory
    } = options

    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = `${itemName}${getDefaultExtension ? getDefaultExtension(itemType) : ''}`
    link.target = '_blank'

    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)

    uni.showToast({
      title: '已在浏览器中开始下载',
      icon: 'success'
    })

    // 模拟下载完成事件
    setTimeout(() => {
      uni.$emit('downloadComplete', {
        id: downloadId,
        gameName: itemName,
        gameType: itemType,
        filePath: null,
        targetDir: getDirectory ? getDirectory(itemType) : options.targetDir,
        browserDownload: true
      })
    }, 3000)
  }


  /**
   * 更新下载进度
   * @param {number} progress 进度百分比
   * @param {number} bytesWritten 已下载字节数
   * @param {number} totalBytes 总字节数
   * @param {string} itemName 项目名称
   * @param {string} itemType 项目类型
   */
  static updateDownloadProgress(progress, bytesWritten, totalBytes, itemName, itemType) {
    const progressText = `${Math.round(progress)}%`
    const sizeText = `${this.formatFileSize(bytesWritten)}/${this.formatFileSize(totalBytes)}`
    
    // 发送进度更新事件
    uni.$emit('downloadProgress', {
      progress: Math.round(progress),
      progressText,
      sizeText,
      bytesWritten,
      totalBytes,
      gameName: itemName,
      gameType: itemType
    })
  }
  
  /**
   * 格式化文件大小
   * @param {number} bytes 字节数
   * @returns {string} 格式化后的大小
   */
  static formatFileSize(bytes) {
    if (bytes === 0) return '0 B'
    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
  }
  
  // ========== 断点续传管理 ==========
  
  /**
   * 保存可恢复的下载信息
   * @param {Object} downloadInfo 下载信息
   */
  static saveResumableDownload(downloadInfo) {
    try {
      const key = `${downloadInfo.itemName}_${downloadInfo.itemType}`
      this.resumableDownloads.set(key, downloadInfo)
      
      // 也保存到本地存储
      const allResumable = {}
      for (let [k, v] of this.resumableDownloads) {
        allResumable[k] = v
      }
      uni.setStorageSync('resumableDownloads', allResumable)
    } catch (error) {
      console.log('保存断点信息失败:', error)
    }
  }
  
  /**
   * 获取可恢复的下载信息
   * @param {string} itemName 项目名称
   * @param {string} itemType 项目类型
   * @returns {Object|null} 下载信息
   */
  static getResumableDownload(itemName, itemType) {
    try {
      const key = `${itemName}_${itemType}`
      
      // 先从内存中查找
      if (this.resumableDownloads.has(key)) {
        return this.resumableDownloads.get(key)
      }
      
      // 从本地存储中加载
      const allResumable = uni.getStorageSync('resumableDownloads') || {}
      if (allResumable[key]) {
        this.resumableDownloads.set(key, allResumable[key])
        return allResumable[key]
      }
      
      return null
    } catch (error) {
      console.log('获取断点信息失败:', error)
      return null
    }
  }
  
  /**
   * 清除可恢复的下载信息
   * @param {string} itemName 项目名称
   * @param {string} itemType 项目类型
   */
  static clearResumableDownload(itemName, itemType) {
    try {
      const key = `${itemName}_${itemType}`
      
      // 从内存中删除
      this.resumableDownloads.delete(key)
      
      // 从本地存储中删除
      const allResumable = uni.getStorageSync('resumableDownloads') || {}
      delete allResumable[key]
      uni.setStorageSync('resumableDownloads', allResumable)
    } catch (error) {
      console.log('清除断点信息失败:', error)
    }
  }
  
  /**
   * 暂停下载
   * @param {string} downloadId 下载 ID
   * @param {string} itemName 项目名称
   * @param {string} itemType 项目类型
   */
  static pauseDownload(downloadId, itemName, itemType) {
    const task = this.activeDownloadTasks.get(downloadId)
    if (task) {
      task.abort()
      
      // 从活跃任务中移除，但保留断点数据
      this.activeDownloadTasks.delete(downloadId)
      
      // 发送暂停事件
      uni.$emit('downloadPaused', { id: downloadId, itemName, itemType })
      
      uni.showToast({
        title: '下载已暂停',
        icon: 'success'
      })
      
      return true
    }
    return false
  }
  
  /**
   * 取消下载
   * @param {string} downloadId 下载 ID
   * @param {boolean} keepData 是否保留数据
   */
  static cancelDownload(downloadId, keepData = false) {
    const task = this.activeDownloadTasks.get(downloadId)
    if (task) {
      task.abort()
    }
    
    // 从活跃任务中移除
    this.activeDownloadTasks.delete(downloadId)
    const cancelHandler = this.downloadCancelHandlers.get(downloadId)
    if (cancelHandler) {
      uni.$off('downloadCancel', cancelHandler)
      this.downloadCancelHandlers.delete(downloadId)
    }
    
    if (!keepData) {
      // 清除断点数据
      const resumableInfo = Object.values(this.resumableDownloads).find(info => info.id === downloadId)
      if (resumableInfo) {
        this.clearResumableDownload(resumableInfo.itemName, resumableInfo.itemType)
      }
    }
    
    // 发送取消事件
    uni.$emit('downloadCancelled', { id: downloadId, keepData })
    
    uni.showToast({
      title: keepData ? '下载已取消，数据已保留' : '下载已取消',
      icon: 'success'
    })
    
    return true
  }
  
  /**
   * 获取所有活跃的下载任务
   */
  static getActiveDownloads() {
    return Array.from(this.activeDownloadTasks.keys())
  }
  
  /**
   * 继续下载
   * @param {string} itemName 项目名称
   * @param {string} itemType 项目类型
   * @returns {boolean} 是否成功开始继续下载
   */
  static resumeDownload(itemName, itemType) {
    const resumableInfo = this.getResumableDownload(itemName, itemType)
    if (resumableInfo) {
      // 重新开始下载
      this.startDownload({
        item: resumableInfo.item,
        itemName: resumableInfo.itemName,
        itemType: resumableInfo.itemType,
        downloadUrl: resumableInfo.downloadUrl,
        targetDir: resumableInfo.targetDir,
        category: 'game', // 暂时硬编码，未来可以从resumableInfo中获取
        historyHandler: null,
        getDirectory: null,
        getDefaultExtension: null
      })
      
      uni.showToast({
        title: '继续下载',
        icon: 'success'
      })
      
      return true
    } else {
      uni.showToast({
        title: '没有可继续的下载',
        icon: 'error'
      })
      return false
    }
  }
  
  /**
   * 获取所有可恢复的下载
   * @returns {Array} 可恢复下载列表
   */
  static getAllResumableDownloads() {
    try {
      const allResumable = uni.getStorageSync('resumableDownloads') || {}
      return Object.values(allResumable)
    } catch (error) {
      console.log('获取所有断点信息失败:', error)
      return []
    }
  }
  
  /**
   * 清空所有断点续传信息
   */
  static clearAllResumableDownloads() {
    try {
      this.resumableDownloads.clear()
      uni.removeStorageSync('resumableDownloads')
      return true
    } catch (error) {
      console.log('清空断点信息失败:', error)
      return false
    }
  }
}

export default DownloadCore